
// #[cfg(windows)]
// use std::os::windows::fs::MetadataExt;
// #[cfg(unix)]
// use std::os::unix::fs::MetadataExt;

use cross_rs::IResult;
use cross_rs::fasttime::b3_datetime::DateTimeFT;
use parse_display::Display;

#[repr(u8)]
#[derive(Copy, Clone, Debug, Display, PartialEq, Eq)]
pub enum EnumPathType {
    #[display("D")]
    Directory = 1,
    #[display("F")]
    File = 2,
    #[display("LD")]
    LinkDirectory = 3,
    #[display("LF")]
    LinkFile = 4,
    #[display("N")]
    None = 0,
}
impl EnumPathType {
    pub fn is_directory(&self) -> bool {
        match self {
            EnumPathType::Directory | EnumPathType::LinkDirectory => true,
            _ => false,
        }
    }
    pub fn is_file(&self) -> bool {
        match self {
            EnumPathType::File | EnumPathType::LinkFile => true,
            _ => false,
        }
    }
    pub fn is_link(&self) -> bool {
        match self {
            EnumPathType::LinkDirectory | EnumPathType::LinkFile => true,
            _ => false,
        }
    }
}


#[derive(Clone)]
pub struct PathAttribute {
    pub dir_root: String,
    pub ptype: EnumPathType,
    pub full: String,
    pub full_parent: String,
    pub name: String,
    pub depth: u32,
    /// Linux不支持
    pub time_created: DateTimeFT,
    pub time_modified: DateTimeFT,
    pub size: u64,
}


impl PathAttribute {
    pub fn full_path(&self) -> String {
        format!("{}{}", self.dir_root, self.full)
    }

    pub fn remove_file(&self) -> IResult<String> {
        let file = self.full_path();
        if self.ptype != EnumPathType::File {
            return Err(format!("不是文件，不能删除！{file}").as_str())?;
        }

        match std::fs::remove_file(&file) {
            Ok(_) => {
                Ok(format!("文件删除成功：{file}"))
            },
            Err(e) => {
                Err(format!("文件删除失败：{file}, {:?}", e).as_str())?
            },
        }
    }
}


impl PathAttribute {
    pub fn to_print(&self) -> String {
        let Self { /*dir_parent , */ptype, full_parent, full, /* name , */ depth, time_created, time_modified, size, .. } = self;
        let size_mb = *size as f64 / 1024_f64 / 1024_f64;
        let str_mb = if size_mb < 10.0 {
            format!("{size_mb:.2}")
        } else if size_mb < 100.0 {
            format!("{size_mb:.1}")
        } else {
            format!("{}", size_mb.round() as i32)
        };
        format!("{ptype}\t{full}\t{depth}\t{size}\t{str_mb}\t{full_parent}\t{}\t{}", time_created.to_print_timezone(), time_modified.to_print_timezone())
    }
}


impl PathAttribute {
    pub fn from_direntry(dir_parent: &str, entry: walkdir::DirEntry) -> IResult<Self> {
        let name = match entry.file_name().to_str() {
            Some(v) => v.to_string(),
            None => {
                return Err("PathAttribute::from_direntry: fail to get file_name")?;
            },
        };
        let full = match entry.path().to_str() {
            Some(v) => {
                v.replace(dir_parent, "").replace("\\", "/")
            },
            None => {
                return Err("PathAttribute::from_direntry: fail to get file_name")?;
            },
        };
        let depth = entry.depth() as u32;
        let full_parent = if depth <= 1 {
            "".to_string()
        } else {
            let parent = full.replace(&name, "");
            let len = parent.len();
            parent[0..len - 1].to_string()
        };

        let meta = entry.metadata()?;

        let ptype = if meta.is_symlink() {
            if meta.is_dir() {
                EnumPathType::LinkDirectory
            } else if meta.is_file() {
                EnumPathType::LinkFile
            } else {
                EnumPathType::None
            }
        } else {
            if meta.is_dir() {
                EnumPathType::Directory
            } else if meta.is_file() {
                EnumPathType::File
            } else {
                EnumPathType::None
            }
        };
        
        let time_modified = DateTimeFT::from_std(meta.modified()?);
        let time_created = match meta.created() {
            Ok(time) => DateTimeFT::from_std(time),
            Err(_) => time_modified,
        };
        
        let size = meta.len();

        Ok(Self { dir_root: dir_parent.to_string(), ptype, full_parent, full, name, depth, time_created, time_modified, size })
    }
}